package org.argus.common.web.core.config;

import org.argus.common.redis.configure.RedissonConfig;
import org.argus.common.web.core.snowflake.BitsAllocator;
import org.argus.common.web.core.snowflake.SnowflakeIdGenerator;
import org.argus.common.web.core.snowflake.WorkerIdAssigner;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;

/**
 * 雪花算法配置
 * The snowflake id has 64bits (long), default allocated as blow:<br>
 * <li>sign: The highest bit is 0
 * <li>delta seconds: The next 34 bits, represents delta seconds since a customer epoch(Supports about 278 years).
 * <li>worker id: The next 13 bits, represents the worker's id which assigns based on database, max id is about 8192
 * <li>sequence: The next 17 bits, represents a sequence within the same second, max for 131072/s<br><br>
 *
 * <pre>{@code
 * +------+----------------------+----------------+--------------+
 * | sign |     delta seconds    | worker node id | sequence     |
 * +------+----------------------+----------------+--------------+
 *   1bit          33bits              13bits         17bits
 * }</pre>
 * @Author 刘文/Cliff Liu
 * @Date 2024/5/19
 */
@Configuration
@ConditionalOnProperty(prefix = "spring.redis", name = "host")
@Import(RedissonConfig.class)
public class SnowflakeConfiguration {

    @Value("${spring.application.name}")
    private String applicationName;

    @Value("${argus.snowflake.deltaSeconds.bitLength:33}")
    private int deltaSecondsLength;

    /**
     * Woker Id bit长度
     */
    @Value("${argus.snowflake.woker.bitLength:13}")
    private int workerIdLength;

    /**
     * Sequence bit 长度
     */
    @Value("${argus.snowflake.sequence.bitLength:17}")
    private int sequenceLength;

    /**
     * 开始计算时间的时间戳秒数，默认 2024-05-20
     */
    @Value("${argus.snowflake.epoch.seconds:1716134400}")
    private long epochSeconds;

    @Bean
    public BitsAllocator bitsAllocator() {
        return new BitsAllocator(deltaSecondsLength, workerIdLength, sequenceLength);
    }

    @Bean
    public WorkerIdAssigner workerIdAssigner(RedissonClient redissonClient) {
        return new WorkerIdAssigner(applicationName, redissonClient, workerIdLength);
    }

    @Bean
    public SnowflakeIdGenerator snowflakeIdGenerator(BitsAllocator bitsAllocator, WorkerIdAssigner workerIdAssigner) {
        return new SnowflakeIdGenerator(epochSeconds, workerIdAssigner, bitsAllocator);
    }
}
